using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using Rogan.Utility.Common;

namespace Rogan.Data
{
    public class DataHelper
    {
        private static readonly Regex KeyReg = new Regex("[^a-zA-Z]", RegexOptions.Compiled);
        /// <summary>
        /// Format SQL
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="leftToken"></param>
        /// <param name="rightToken"></param>
        /// <returns></returns>
        public static string FormatSql(string sql, char leftToken, char rightToken)
        {
            if (sql == null)
            {
                return string.Empty;
            }
            sql = sql.Replace("{0}", leftToken.ToString()).Replace("{1}", rightToken.ToString());
            return sql;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static string FormatValue(object val)
        {
            if (val == null || val == DBNull.Value)
            {
                return "null";
            }
            Type type = val.GetType();
            if (type == typeof(DateTime) || type == typeof(Guid))
            {
                return string.Format("'{0}'", val);
            }
            if (type == typeof(TimeSpan))
            {
                DateTime dateTime = new DateTime(1900, 1, 1);
                return string.Format("(cast('{0}' as datetime) - cast('{1}' as datetime))", dateTime + (TimeSpan)val, dateTime);
            }
            if (type == typeof(bool))
            {
                if (!(bool)val)
                {
                    return "0";
                }
                return "1";
            }
            else
            {
                if (val is Field)
                {
                    return ((Field)val).FieldNameWithTable;
                }
                if (type.IsEnum)
                {
                    return Convert.ToInt32(val).ToString();
                }
                if (type.IsValueType)
                {
                    return val.ToString();
                }
                return "N'" + val.ToString().Replace("'", "''") + "'";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object Clone(object obj)
        {
            object result;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(memoryStream, obj);
                memoryStream.Position = 0L;
                result = binaryFormatter.Deserialize(memoryStream);
            }
            return result;
        }

        /// <summary>
        /// Convert List
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static IEnumerable<TTarget> ConvertList<TSource, TTarget>(List<TSource> list)
        {
            List<TTarget> retList = new List<TTarget>();
            foreach (TSource current in list)
            {
                retList.Add((TTarget)ConvertValue(typeof(TTarget), current));
            }
            return retList;
        }
        public static IEnumerable ListDataToEnumerable<TSource>(List<TSource> list, Type targetType)
        {
            IEnumerable result;
            if (targetType == typeof(int))
            {
                result = ConvertList<TSource, int>(list);
            }
            else
            {
                if (targetType == typeof(double))
                {
                    result = ConvertList<TSource, double>(list);
                }
                else
                {
                    if (targetType == typeof(decimal))
                    {
                        result = ConvertList<TSource, decimal>(list);
                    }
                    else
                    {
                        if (targetType == typeof(string))
                        {
                            result = ConvertList<TSource, string>(list);
                        }
                        else
                        {
                            if (targetType == typeof(byte[]))
                            {
                                result = ConvertList<TSource, byte[]>(list);
                            }
                            else
                            {
                                result = ConvertList<TSource, object>(list);
                            }
                        }
                    }
                }
            }
            return result;
        }
        private static bool CheckStruct(Type type)
        {
            return type.IsValueType && !type.IsEnum && !type.IsPrimitive && !type.IsSerializable;
        }
        public static object ConvertValue(Type type, object value)
        {
            if (Convert.IsDBNull(value) || value == null)
            {
                return null;
            }
            if (CheckStruct(type))
            {
                string data = value.ToString();
                return SerializationManager.Deserialize(type, data);
            }
            Type type2 = value.GetType();
            if (type == type2)
            {
                return value;
            }
            if ((type == typeof(Guid) || type == typeof(Guid?)) && type2 == typeof(string))
            {
                if (string.IsNullOrEmpty(value.ToString()))
                {
                    return null;
                }
                return new Guid(value.ToString());
            }
            else
            {
                if ((type == typeof(DateTime) || type == typeof(DateTime?)) && type2 == typeof(string))
                {
                    if (string.IsNullOrEmpty(value.ToString()))
                    {
                        return null;
                    }
                    return Convert.ToDateTime(value);
                }
                else
                {
                    if (type.IsEnum)
                    {
                        try
                        {
                            object result = Enum.Parse(type, value.ToString(), true);
                            return result;
                        }
                        catch
                        {
                            object result = Enum.ToObject(type, value);
                            return result;
                        }
                    }
                    if (type != typeof(bool) && type != typeof(bool?))
                    {
                        if (type.IsGenericType)
                        {
                            type = type.GetGenericArguments()[0];
                        }
                        return Convert.ChangeType(value, type);
                    }
                    bool flag = false;
                    if (bool.TryParse(value.ToString(), out flag))
                    {
                        return flag;
                    }
                    if (string.IsNullOrEmpty(value.ToString()))
                    {
                        return false;
                    }
                    return true;
                }
            }
        }
        public static TResult ConvertValue<TResult>(object value)
        {
            if (Convert.IsDBNull(value) || value == null)
            {
                return default(TResult);
            }
            object obj = ConvertValue(typeof(TResult), value);
            if (obj == null)
            {
                return default(TResult);
            }
            return (TResult)obj;
        }
        public static object FastMethodInvoke(object obj, MethodInfo method, params object[] parameters)
        {
            return DynamicCalls.GetMethodInvoker(method)(obj, parameters);
        }
        public static T Create<T>()
        {
            return (T)Create(typeof(T))();
        }
        public static FastCreateInstanceHandler Create(Type type)
        {
            return DynamicCalls.GetInstanceCreator(type);
        }
        public static void SetPropertyValue(object obj, PropertyInfo property, object value)
        {
            if (property.CanWrite)
            {
                FastPropertySetHandler propertySetter = DynamicCalls.GetPropertySetter(property);
                value = ConvertValue(property.PropertyType, value);
                propertySetter(obj, value);
            }
        }
        public static void SetPropertyValue(object obj, string propertyName, object value)
        {
            SetPropertyValue(obj.GetType(), obj, propertyName, value);
        }
        public static void SetPropertyValue(Type type, object obj, string propertyName, object value)
        {
            PropertyInfo property = type.GetProperty(propertyName);
            if (property != null)
            {
                SetPropertyValue(obj, property, value);
            }
        }
        public static object GetPropertyValue<T>(T entity, string propertyName)
        {
            PropertyInfo property = entity.GetType().GetProperty(propertyName);
            if (property != null)
            {
                return property.GetValue(entity, null);
            }
            return null;
        }
        public static DataTable EntityArrayToDataTable<T>(T[] entities) where T : Entity
        {
            DataTable dataTable = new DataTable();
            if (entities == null || entities.Length == 0)
            {
                return dataTable;
            }
            Field[] fields = entities[0].GetFields();
            int num = fields.Length;
            Field[] array = fields;
            for (int i = 0; i < array.Length; i++)
            {
                Field field = array[i];
                dataTable.Columns.Add(field.Name);
            }
            for (int j = 0; j < entities.Length; j++)
            {
                T t = entities[j];
                DataRow dataRow = dataTable.NewRow();
                object[] values = t.GetValues();
                for (int k = 0; k < num; k++)
                {
                    dataRow[fields[k].Name] = values[k];
                }
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }
        public static string MakeUniqueKey(string prefix)
        {
            byte[] array = new byte[16];
            new RNGCryptoServiceProvider().GetBytes(array);
            string text = KeyReg.Replace(Convert.ToBase64String(array).Trim(), string.Empty);
            if (text.Length > 16)
            {
                return text.Substring(0, 16).ToLower();
            }
            return text.ToLower();
        }
        public static Dictionary<Field, object> FieldValueToDictionary(Field[] fields, object[] values)
        {
            Dictionary<Field, object> dictionary = new Dictionary<Field, object>();
            if (fields == null || fields.Length == 0)
            {
                return dictionary;
            }
            int num = fields.Length;
            for (int i = 0; i < num; i++)
            {
                dictionary.Add(fields[i], values[i]);
            }
            return dictionary;
        }
        public static string GetOperatorQueryText(QueryOperator op)
        {
            switch (op)
            {
                case QueryOperator.Equal:
                    return " = ";
                case QueryOperator.NotEqual:
                    return " <> ";
                case QueryOperator.Greater:
                    return " > ";
                case QueryOperator.Less:
                    return " < ";
                case QueryOperator.GreaterOrEqual:
                    return " >= ";
                case QueryOperator.LessOrEqual:
                    return " <= ";
                case QueryOperator.Like:
                    return " LIKE ";
                case QueryOperator.And:
                    return " and ";
                case QueryOperator.Or:
                    return " or ";
                case QueryOperator.BitwiseAND:
                    return " & ";
                case QueryOperator.BitwiseOR:
                    return " | ";
                case QueryOperator.BitwiseXOR:
                    return " ^ ";
                case QueryOperator.BitwiseNOT:
                    return " ~ ";
                case QueryOperator.IsNULL:
                    return " IS NULL ";
                case QueryOperator.IsNotNULL:
                    return " IS NOT NULL ";
                case QueryOperator.Add:
                    return " + ";
                case QueryOperator.Subtract:
                    return " - ";
                case QueryOperator.Multiply:
                    return " * ";
                case QueryOperator.Divide:
                    return " / ";
                case QueryOperator.Modulo:
                    return " % ";
                case QueryOperator.In:
                    return " in ";
                case QueryOperator.NotIn:
                    return " not in ";
                default:
                    throw new NotSupportedException("Unknown QueryOperator: " + op + "!");
            }
        }
        public static WhereExpression GetPrimaryKeyWhere(Entity entity)
        {
            Field[] primaryKeyFields = entity.GetPrimaryKeyFields();
            WhereExpression whereExpression = new WhereExpression();

            for (int i = 0; i < primaryKeyFields.Length; i++)
            {
                Field field = primaryKeyFields[i];
                WhereExpression whereExpression2 = field == entity.GetValue(field.PropertyName);
                if (WhereExpression.IsNullOrEmpty(whereExpression))
                {
                    whereExpression = whereExpression2;
                }
                else
                {
                    whereExpression = WhereExpression.Create(whereExpression, whereExpression2, QueryOperator.And);
                }
            }
            return whereExpression;
        }
        public static WhereExpression GetPrimaryKeyWhere<T>(object[] pkValues) where T : Entity
        {
            T table = EntityHelper.GetTable<T>();
            Field[] primaryKeyFields = table.GetPrimaryKeyFields();
            WhereExpression whereExpression = new WhereExpression();
            for (int i = 0; i < primaryKeyFields.Length; i++)
            {
                Field field = primaryKeyFields[i];
                object value = pkValues[i];
                if (WhereExpression.IsNullOrEmpty(whereExpression))
                {
                    whereExpression = (field == value);
                }
                else
                {
                    whereExpression = WhereExpression.Create(whereExpression, field == value, QueryOperator.Or);
                }
            }
            return whereExpression;
        }
    }
}
